package lab5;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;

public class GoS {
	static ArrayList<String> species;
	static ArrayList<char[]> DNA;
	static HashMap<Character, Integer> letterIndex;
	static int[][] scoreMatrix;
	static int gapPenalty;

	public static void main(String[] args) {
		HashMap<String, Integer> correctResult = new HashMap<String, Integer>();
		String line = "";
		String[] str = new String[1];
		species = new ArrayList<String>();
		DNA = new ArrayList<char[]>();
		letterIndex = new HashMap<Character, Integer>();
		scoreMatrix = new int[1][1];
		
		try{
			FileInputStream is = new FileInputStream(args[0]);
			BufferedReader br  = new BufferedReader(new InputStreamReader(is));
			int loops = 0;
			
			while((line = br.readLine()) != null) {
				if(!line.startsWith("#")) {
					str = line.split("   |  | ");
					if(loops == 0) {
						for(int index = 1;index < str.length ; index++) {
							letterIndex.put(str[index].charAt(0), index);
							System.out.println(str[index].charAt(0) + " " +  (index));
						}
						scoreMatrix = new int[str.length][str.length];
						System.out.println();
					}else {
						for(int i = 1; i < str.length; i++) {
							scoreMatrix[loops][i] = Integer.parseInt(str[i]);
							System.out.print(Integer.parseInt(str[i]) + " ");
						}
						System.out.println();
					}
					
					loops++;
				}
			}
			
			
			is.close();
			is = new FileInputStream(args[1]);
			br = new BufferedReader(new InputStreamReader(is));
			String dna = "";
			boolean firstLine = true;
			
			while((line = br.readLine()) != null && !line.equals("")) {
				str = line.split(">|  | ");
				
				if(str[0].equals("")) {
					if(firstLine) {
						firstLine = false;
					}else {
						DNA.add(dna.toCharArray());
						dna =  "";
					}
					
					species.add(str[1]);
				}else {
					dna = dna.concat(str[0]);
				}
			}
			
			DNA.add(dna.toCharArray());
			is.close();
			
			is = new FileInputStream(args[2]);
			br = new BufferedReader(new InputStreamReader(is));
			String invertedPair;
			int score;
			
			while((line = br.readLine()) != null && !line.equals("")) {
				str = line.split(" ");
				if(str.length != 1) {
					invertedPair = "";
					score = Integer.parseInt(str[1]);
					correctResult.put(str[0], score);
					str = str[0].split("--|:");
					invertedPair = invertedPair.concat(str[1]);
					invertedPair = invertedPair.concat("--");
					invertedPair = invertedPair.concat(str[0]);
					invertedPair = invertedPair.concat(":");
					correctResult.put(invertedPair, score);
				}
//				System.out.println("str[0] " + str[0]);
//				System.out.println("str[1] " + str[1]);
				//System.out.println("str[2] " + str[2]);
			}
			
			br.close();
			is.close();

		
		}catch (IOException e) {
			e.printStackTrace();
		}
		
		gapPenalty = scoreMatrix[letterIndex.get('*')][1];
		System.out.println("\nGap penalty " + gapPenalty + "\n");
		String pairOfSpecies = "";
		int correctScore, score;
		boolean matchOutputFile = true;
		
		for(int i = 0; i < DNA.size(); i++) {
			for(int j = i + 1; j < DNA.size(); j++){
				pairOfSpecies = "";
				pairOfSpecies = pairOfSpecies.concat(species.get(i));
				pairOfSpecies = pairOfSpecies.concat("--");
				pairOfSpecies = pairOfSpecies.concat(species.get(j));
				pairOfSpecies = pairOfSpecies.concat(":");
				System.out.print(pairOfSpecies);
				
				score = Alignment(DNA.get(i), DNA.get(j));
				correctScore = correctResult.get(pairOfSpecies);
				if(score != correctScore) {
					System.out.println("ERROR! Correct score: " + correctScore + " " + pairOfSpecies + "\n");
					matchOutputFile = false;
				}
			}
		}
		
		if(matchOutputFile)
			System.out.println("\nScores match the out-file\n");
		else
			System.out.println("\nScores doesn't match the out-file\n");
	}
	
	private static int Alignment(char[] X, char[] Y) {
		int m = X.length, n = Y.length;
		int[][] A  = new int[m + 1][n + 1];
		for(int i = 0; i <= m; i++) {
			A[i][0] = gapPenalty * i;
		}
		
		for(int j = 0; j <= n; j++) {
			A[0][j] = gapPenalty * j;
		}
		
//		System.out.println();
//		for(int i = 0; i <= m; i++) {
//			for(int j = 0; j <= n; j++) {
//				System.out.print(A[i][j] + " ");
//			}
//			System.out.println();
//		}
		
		for(int j = 1; j <= n; j++){
			for(int i = 1; i <= m; i++) {
				//System.out.println("[j - 1] " + Y[j - 1]);
				A[i][j] = OPT(i, j, A, X[i - 1],Y[j - 1]);
			}
		}
		
		System.out.println(" " + A[m][n]);
		//System.out.println("m " + m + " n " + n);
		
//		System.out.println("\nA:");
//		for(int i = 0; i <= m; i++) {
//			for(int j = 0; j <= n; j++) {
//				System.out.print(A[i][j] + " ");
//			}
//			System.out.println();
//		}
		
		String XAlignment = "";
		String YAlignment = "";
		int i = m, j = n;
		
		while(i > 0 && j > 0) {
			if(A[i][j] - scoreMatrix[letterIndex.get(X[i - 1])]
					[letterIndex.get(Y[j - 1])] == A[i - 1][j - 1]) {
				XAlignment = Character.toString(X[i - 1]).concat(XAlignment);
				YAlignment = Character.toString(Y[j - 1]).concat(YAlignment);
				i--;
				j--;
			}else if(A[i][j] - gapPenalty == A[i][j - 1]) {
				XAlignment = "-".concat(XAlignment);
				YAlignment = Character.toString(Y[j - 1]).concat(YAlignment);
				j--;
			}else if(A[i][j] - gapPenalty == A[i - 1][j]) {
				XAlignment = Character.toString(X[i - 1]).concat(XAlignment);
				YAlignment = "-".concat(YAlignment);
				i--;
			}
		}
		
		while(j > 0) {
			XAlignment = "-".concat(XAlignment);
			YAlignment = Character.toString(Y[j - 1]).concat(YAlignment);
			j--;
		}
		while(i > 0){
			XAlignment = Character.toString(X[i - 1]).concat(XAlignment);
			YAlignment = "-".concat(YAlignment);
			i--;
		}
		
		System.out.println(XAlignment + "\n" + YAlignment + "\n");
		return A[m][n];
	}
	
	private static int OPT(int i, int j, int[][] A, char x, char y) {
		int alpha = scoreMatrix[letterIndex.get(x)][letterIndex.get(y)];
		//System.out.println("x " + x + " y " + y + " " + "alpha " + alpha + " i " + i + " j " + j);
		int match = alpha + A[i-1][j-1];
		int XGap = gapPenalty + A[i-1][j];
		int YGap = gapPenalty + A[i][j-1];
		
		if(match >= XGap && match >= YGap) {
			//System.out.println("match " + match);
			return match;
		}else if(XGap >= match && XGap >= YGap) {
			//System.out.println("XGap " + XGap);
			return XGap;
		}else {
			//System.out.println("Ygap " + YGap + " XGap " + XGap + " match " + match);
			return YGap;
		}
	}

}
